package org.springblogs.batch.config.stock;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springblogs.batch.listener.JobCompletionNotificationListener;
import org.springblogs.core.Model;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.batch.item.data.RepositoryItemReader;
import org.springframework.batch.item.data.RepositoryItemWriter;
import org.springframework.batch.item.data.builder.RepositoryItemReaderBuilder;
import org.springframework.batch.item.data.builder.RepositoryItemWriterBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.repository.PagingAndSortingRepository;

public abstract class AbstractRepositoryBatchJob<I extends Model, O extends Model> {
	@Autowired
	protected JobBuilderFactory jobBuilderFactory;
	@Autowired
	protected StepBuilderFactory stepBuilderFactory;
	@Autowired
	protected JobCompletionNotificationListener listener;

	private String name = this.getClass().getSimpleName();

	public abstract PagingAndSortingRepository<I, ?> getReadRepository();

	public PagingAndSortingRepository<O, ?> getWriteRepository() {
		return null;
	}

	protected String getReaderMethod() {
		return "findAll";
	}

	protected List<Object> getReaderArgs() {
		return new ArrayList<>();
	}

	protected RepositoryItemReader<I> getReader() {
		Map<String, Direction> sorts = new HashMap<>();
		sorts.put("updatedDate", Direction.ASC);
		return new RepositoryItemReaderBuilder<I>()//
				.name(String.format("%sItemReader", name))//
				.repository(getReadRepository())//
				.methodName(getReaderMethod())//
				.arguments(getReaderArgs())//
				.sorts(sorts)//
				.build();
	}

	public Job getJob() {
		return jobBuilderFactory.get(name)//
				.incrementer(new RunIdIncrementer())//
				.listener(listener)//
				.flow(step())//
				.end()//
				.build();

	}

	protected abstract ItemProcessor<I, O> processor();

	protected String getWriterMethod() {
		return "save";
	}

	protected RepositoryItemWriter<O> getWriter() {
		return new RepositoryItemWriterBuilder<O>()//
				.repository(getWriteRepository())//
				.methodName(getWriterMethod())//
				.build();
	}

	protected Step step() {
		return stepBuilderFactory//
				.get(String.format("%sStep", name))//
				.<I, O> chunk(10)//
				.reader(getReader())//
				.processor(processor())//
				//.writer(getWriter())//
				.allowStartIfComplete(true)//
				.build();
	}
}
